package gmapimagecutter;


import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.Toolkit;
import java.awt.Transparency;
import java.awt.image.BufferedImage;
import java.awt.image.CropImageFilter;
import java.awt.image.FilteredImageSource;
import java.awt.image.ImageFilter;
import java.io.File;
import java.io.IOException;

import javax.imageio.ImageIO;

import imagetoolscommon.LngLat;
import imagetoolscommon.Point;

public class TileUtils {

    private Point start;    //坐上角坐标
    private Point end;      //右下角坐标
    private int minLevel;   //最小级别
    private int maxLevel;   //最大级别
    private String pic;     //图片地址


    public TileUtils(Point start, Point end, int minLevel, int maxLevel, String pic) {
        this.pic = pic;
        this.start = start;
        this.end = end;
        this.minLevel = minLevel;
        this.maxLevel = maxLevel;
    }

	/**
	 * 获取中心点对应网格编号
	 * @param longitude
	 * @param latitude
	 * @param level
	 * @return
	 */
	public static Point lnglatToTile(double longitude, double latitude, int level){
		double tileX = _lngToTileX(longitude, level);
		double tileY = _latToTileY(latitude, level);
		return new Point(tileX, tileY);
	}

	/**
	 * 获取中心点对应的像素坐标（相对于当前单元格）
	 * @param longitude
	 * @param latitude
	 * @param level
	 * @return
	 */
	public static Point lnglatToPixel(double longitude, double latitude, int level){
		double pixelx = _lngToPixelX(longitude, level);
		double pixelY = _latToPixelY(latitude, level);
		return new Point(pixelx, pixelY);
	}

	/**
	 * 获取中心点对应的像素坐标（相对于当前整个世界）
	 * @param longitude
	 * @param latitude
	 * @param level
	 * @return
	 */
	public static Point lnglatToGlobalPixel(double longitude, double latitude, int level){
		Point tile = lnglatToTile(longitude, latitude, level);
		Point pixel = lnglatToPixel(longitude, latitude, level);
		double pixelX = _tileToPoint(tile.getX(), pixel.getX(), level);
		double pixelY = _tileToPoint(tile.getY(), pixel.getY(), level);
		return new Point(pixelX, pixelY);
	}

	public static double _lngToTileX(double longitude, int level){
		double x = (longitude + 180) / 360;
	    double tileX = Math.floor(x * _getMapSize(level));
	    return tileX;
	}

	public static double _latToTileY(double latitude, int level){
		 double lat_rad = latitude * Math.PI / 180;
		 double y = (1 - Math.log(Math.tan(lat_rad) + 1 / Math.cos(lat_rad)) / Math.PI) / 2;
		 double tileY = Math.floor(y * _getMapSize(level));
	      // 代替性算法,使用了一些三角变化，其实完全等价
	      //let sinLatitude = Math.sin(latitude * Math.PI / 180);
	      //let y = 0.5 - Math.log((1 + sinLatitude) / (1 - sinLatitude)) / (4 * Math.PI);
	      //let tileY = Math.floor(y * this._getMapSize(level));
	      return tileY;
	}

	public static double _lngToPixelX(double longitude, int level){
		double x = (longitude + 180) / 360;
		double pilex = Math.floor(x * _getMapSize(level) * 256 % 256);
		return pilex;
	};

	public static double _latToPixelY(double latitude, int level){
		double sinLatitude = Math.sin(latitude * Math.PI / 180);
		double y = 0.5 - Math.log((1 + sinLatitude) / (1 - sinLatitude)) / (4 * Math.PI);
		double pixelY = Math.floor(y * _getMapSize(level) * 256 % 256);
	    return pixelY;
	}

	public static double _getMapSize(int level){
		return Math.pow(2, level);
	};

	public static double _tileToPoint(double tile, double pixel, int level){
		return tile * 256 + pixel;
//		double globalPixel = DoubleUtil.div((tile * 256 + pixel), Math.pow(2, level - 18));
//		System.out.println("++++++ "+globalPixel);
//		return globalPixel;
	}

	public void cutAllLevel() throws IOException {
        for (int i = minLevel; i <= maxLevel; i++) {
            cutOneLevel(i);
        }
    }

	public void cutOneLevel(int level) throws IOException {
        System.out.println(level +"级别开始切图+++++++++++++");
        String pic = this.pic;
        String[] dirArr = pic.split("\\\\");
        String tempFileName = dirArr[dirArr.length-1].split("\\.")[0];
        String dir = pic.replace(dirArr[dirArr.length-1], "");
        double startX = start.getX();
        double startY = start.getY();
        double endX = end.getX();
        double endY = end.getY();

        String levelDirName = dir + "\\" + tempFileName+ "\\tiles\\" + level + "\\";
        File levelDir = new File(levelDirName);
        if (!levelDir.exists() && !levelDir.isDirectory()) {
            boolean mkdirs = levelDir.mkdirs();
            if(!mkdirs) {
                throw new IOException("创建目录失败："+level);
            }
        }


        //开始
        Point mcPoint = lnglatToTile(startX, startY, level);
        System.out.println(mcPoint);
        Point pxPoint = lnglatToPixel(startX, startY, level);	//中心点对应的像素坐标(当前网格 0 - 256)
        System.out.println(pxPoint);

        //结束
        Point mcPointEnd = lnglatToTile(endX, endY, level);
        System.out.println(mcPointEnd);
        Point pxPointEnd = lnglatToPixel(endX, endY, level);	//中心点对应的像素坐标(当前网格 0 - 256)
        System.out.println(pxPointEnd);

        int x = (int)(mcPointEnd.getX() - mcPoint.getX()) + 1;
        int y = (int)(mcPointEnd.getY() - mcPoint.getY()) + 1;
        System.out.println(x + " " + y);

        //图片放大缩小到指定大小
        int width = x * 256 - ((int)pxPoint.getX() + (256 - (int)pxPointEnd.getX()));
        int height = y * 256 - ((int)pxPoint.getY() + (256 - (int)pxPointEnd.getY()));
        System.out.println(width + " " + height);

        //图片扩展到指定大小
        int extendLeft = (int)pxPoint.getX();
        int extendRight = 256 - (int)pxPointEnd.getX();
        int extendUp = (int)pxPoint.getY();
        int extendDown = 256 - (int)pxPointEnd.getY();
        System.out.println(extendLeft + " " + extendRight + " " + extendUp+ " " + extendDown);
        int totalWidth = 256 * x;
        int totalHeight = 256 * y;


        BufferedImage bi = ImageIO.read(new File(pic));
        Graphics2D g = bi.createGraphics();
        BufferedImage extend = g.getDeviceConfiguration().createCompatibleImage(totalWidth, totalHeight, Transparency.TRANSLUCENT);
        g.dispose();
        g = extend.createGraphics();
        g.drawImage(extend, 0, 0, totalWidth, totalHeight, null);
        g.drawImage(bi, extendLeft, extendUp, width, height, null);
        ImageIO.write(extend, "png", new File(levelDirName + "base.png"));	//保存扩展后的图片



        Image image = extend.getScaledInstance(totalWidth, totalHeight, Image.SCALE_DEFAULT);
        int count = 1;
        for(int i = 0; i < x; i ++){
            for(int j = 0; j < y; j ++){
                String fileName = levelDirName + ((int)mcPoint.getX() + i) + "_" + ((int)mcPoint.getY() + j) + ".png";
                ImageFilter cropfilter = new CropImageFilter(256 * i, 256 * j, 256, 256);
                Image img = Toolkit.getDefaultToolkit().createImage(new FilteredImageSource(image.getSource(), cropfilter));
                BufferedImage tag = new BufferedImage(256, 256, BufferedImage.TYPE_INT_BGR);
                Graphics2D gs = tag.createGraphics();
                tag = gs.getDeviceConfiguration().createCompatibleImage(256, 256, Transparency.TRANSLUCENT);
                gs.dispose();
                gs = tag.createGraphics();
                gs.drawImage(img, 0, 0, null);
                g.dispose();
                ImageIO.write(tag, "png", new File(fileName));
                System.out.println("+++++++++++++" + fileName + " " +count +"/"+ (x*y));
                count++;
            }
        }
    }


    public static void main(String[] args) throws IOException {

	    //左上角&右下角坐标
	    Point start = new Point(105.6527059059141, 26.022261791536547);
        Point end = new Point(105.68989205169629, 25.929631345626735);
        String file = "D:\\test\\hgs1.png";

        //奇遇岭
//        Point start = new Point(105.47982680606741, 25.92442812452184);
//        Point end = new Point(105.5083816032404, 25.894695163339605);
//        String file = "D:\\test\\qyl100.png";


        //
//        Point start = new Point(105.9107129554747, 26.075025770574665);
//        Point end = new Point(106.52166946792685, 25.324061753103215);
//        String file = "D:\\test\\ziyun100.png";

//
//        Point start = new Point(106.24063914138784, 25.697116901172357);
//        Point end = new Point(106.2817512359615, 25.67380020709812);
//        String file = "D:\\test\\gth100.png";



	    TileUtils utils = new TileUtils(start, end, 18, 18, file);
//      utils.cutOneLevel(14);
        utils.cutAllLevel();
    }

}
